package com.nnnu.wsnackshop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nnnu.wsnackshop.exception.ObjectException;
import com.nnnu.wsnackshop.handler.CustomRowHeightWriteHandler;
import com.nnnu.wsnackshop.handler.CustomSheetWriteHandler;
import com.nnnu.wsnackshop.listener.ImageDataConverter;
import com.nnnu.wsnackshop.listener.ProductImportListener;
import com.nnnu.wsnackshop.mapper.*;
import com.nnnu.wsnackshop.pojo.dto.*;
import com.nnnu.wsnackshop.pojo.entity.*;
import com.nnnu.wsnackshop.pojo.vo.ProductExportVO;
import com.nnnu.wsnackshop.pojo.vo.ProductVO;
import com.nnnu.wsnackshop.result.PageResult;
import com.nnnu.wsnackshop.service.IPromotionsService;
import com.nnnu.wsnackshop.service.IProductsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nnnu.wsnackshop.utils.AliOssUtil;
import com.nnnu.wsnackshop.utils.ImageUtils;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import com.nnnu.wsnackshop.pojo.vo.ProductDetailVO;
import com.nnnu.wsnackshop.pojo.vo.SkuVO;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-05-14
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ProductsServiceImpl extends ServiceImpl<ProductsMapper, Products> implements IProductsService {

    private final StoresMapper storesMapper;
    private final CategoriesMapper categoriesMapper;
    private final AliOssUtil ossService;
    private final ProductBrandsMapper brandMapper;
    private final ProductSpuMapper spuMapper;
    private final ProductSkuMapper productSkuMapper;
    private final ObjectMapper objectMapper;
    private final OrderItemsMapper orderItemsMapper;
    private final OrdersMapper ordersMapper;
    private final IPromotionsService promotionsService;
    private final ReviewsMapper reviewsMapper;

    @Override
    public PageResult<ProductVO> pageProducts(ProductPageDTO dto) {
        Page<Products> page = new Page<>(dto.getPageNum(), dto.getPageSize());

        // 处理排序方向
        String sortOrder = "desc";
        if (StrUtil.isNotBlank(dto.getSortOrder()) && "asc".equalsIgnoreCase(dto.getSortOrder())) {
            sortOrder = "asc";
        }

        // 使用自定义SQL查询，支持直接在数据库中排序
        List<Products> products = baseMapper.findProductsWithSort(
                page,
                dto.getName(),
                dto.getStatus(),
                dto.getStoreId(),
                dto.getCategoryId(),
                dto.getSpuId(),
                dto.getMinPrice(),
                dto.getMaxPrice(),
                dto.getSortBy(),
                sortOrder);

        // 设置查询结果到page对象
        page.setRecords(products);

        // 转换为VO
        List<ProductVO> vos = products.stream().map(this::toVO).collect(Collectors.toList());

        return PageResult.<ProductVO>builder()
                .total(page.getTotal())
                .items(vos)
                .build();
    }

    @Override
    public void addProduct(AddProductDTO dto) {
        Products entity = BeanUtil.copyProperties(dto, Products.class);
        entity.setStatus(dto.getStatus() == null ? 1 : dto.getStatus());
        entity.setSpuId(dto.getSpuId());
        baseMapper.insert(entity);
    }

    @Override
    public void updateProduct(UpdateProductDTO dto) {
        Products entity = baseMapper.selectById(dto.getId());
        if (entity == null)
            throw new ObjectException("商品不存在: " + dto.getId());
        BeanUtil.copyProperties(dto, entity);
        entity.setSpuId(dto.getSpuId());
        baseMapper.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProducts(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids))
            throw new ObjectException("删除ID列表不能为空");
        baseMapper.deleteBatchIds(ids.stream().distinct().toList());
    }

    @Override
    public void updateStatus(Integer id, Integer status) {
        Products entity = baseMapper.selectById(id);
        if (entity == null)
            throw new ObjectException("商品不存在: " + id);
        entity.setStatus(status);
        baseMapper.updateById(entity);
    }

    @Override
    public ProductVO getProductDetail(Integer id) {
        Products entity = baseMapper.selectById(id);
        if (entity == null)
            throw new ObjectException("商品不存在: " + id);
        return toVO(entity);
    }

    private ProductVO toVO(Products product) {
        ProductVO vo = BeanUtil.copyProperties(product, ProductVO.class);
        vo.setSpuId(product.getSpuId());
        Optional.ofNullable(storesMapper.selectById(product.getStoreId())).map(Stores::getName)
                .ifPresent(vo::setStoreName);
        Optional.ofNullable(brandMapper.selectById(product.getBrandId())).map(ProductBrands::getName)
                .ifPresent(vo::setBrand);
        Optional.ofNullable(categoriesMapper.selectById(product.getCategoryId())).map(Categories::getName)
                .ifPresent(vo::setCategoryName);
        if (product.getSpuId() != null) {
            Optional.ofNullable(spuMapper.selectById(product.getSpuId()))
                    .map(ProductSpu::getTitle)
                    .ifPresent(vo::setSpuTitle);
        }

        // 处理商品多图
        if (StrUtil.isNotBlank(product.getImages())) {
            try {
                List<String> imagesList = objectMapper.readValue(product.getImages(),
                        new TypeReference<>() {
                        });
                vo.setImages(imagesList);
            } catch (IOException e) {
                log.error("商品多图JSON反序列化失败: {}", product.getImages(), e);
                vo.setImages(new ArrayList<>()); // 失败时设置为空列表
            }
        } else {
            vo.setImages(new ArrayList<>());
        }

        // 从 SKU 获取价格信息
        LambdaQueryWrapper<ProductSku> skuQw = Wrappers.<ProductSku>lambdaQuery()
                .eq(ProductSku::getProductId, product.getId())
                .eq(ProductSku::getSaleable, true)
                .eq(ProductSku::getValid, true);
        List<ProductSku> skus = productSkuMapper.selectList(skuQw);

        // 初始化价格和折扣
        BigDecimal finalPrice = BigDecimal.ZERO;
        BigDecimal originalMaxPrice = BigDecimal.ZERO;
        int discountPercentage = 100; // 默认无折扣

        if (!CollectionUtils.isEmpty(skus)) {
            // 找到最低价格的 SKU 作为基础价格
            Optional<BigDecimal> minSkuPrice = skus.stream()
                    .map(ProductSku::getPrice)
                    .filter(Objects::nonNull)
                    .min(BigDecimal::compareTo);

            finalPrice = minSkuPrice.orElse(BigDecimal.ZERO); // 如果没有最低价格，则为0
            originalMaxPrice = skus.stream()
                    .map(ProductSku::getPrice)
                    .filter(Objects::nonNull)
                    .max(BigDecimal::compareTo)
                    .orElse(finalPrice); // 如果没有最高价格，则为最低价格

            // 设置默认skuId
            vo.setSkuId(skus.get(0).getId());

            // 查询适用于当前商品的促销活动
            List<Promotions> promotions = promotionsService.getActivePromotionsForProduct(product.getId(),
                    product.getCategoryId());

            // 应用促销活动，选择最优折扣
            for (Promotions promo : promotions) {
                try {
                    JsonNode detailsNode = objectMapper.readTree(promo.getDetails());
                    if (detailsNode.has("discountPercentage")) {
                        int currentDiscount = detailsNode.get("discountPercentage").asInt();
                        BigDecimal discountedPrice = finalPrice.multiply(BigDecimal.valueOf(currentDiscount))
                                .divide(BigDecimal.valueOf(100), 2, java.math.RoundingMode.HALF_UP);

                        // 如果当前折扣更优惠（价格更低），则更新价格和折扣信息
                        if (discountedPrice.compareTo(finalPrice) < 0) {
                            finalPrice = discountedPrice;
                            discountPercentage = currentDiscount;
                        }
                    }
                } catch (IOException e) {
                    log.warn("解析促销活动详情失败: {}", promo.getDetails(), e);
                }
            }
        }
        vo.setPrice(finalPrice);
        vo.setOriginalPrice(originalMaxPrice);
        vo.setDiscount(discountPercentage);

        // 计算商品总库存
        int totalStock = 0;
        if (!CollectionUtils.isEmpty(skus)) {
            totalStock = skus.stream()
                    .mapToInt(sku -> Optional.ofNullable(sku.getStock()).orElse(0))
                    .sum();
        }
        vo.setStock(totalStock);

        // 计算商品销量
        int totalSales = 0;
        // 获取与当前产品关联的所有SKU的ID列表
        List<Integer> skuIds = skus.stream().map(ProductSku::getId).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(skuIds)) {
            // 获取所有与当前SKU关联的订单项
            List<OrderItems> orderItems = orderItemsMapper.selectList(Wrappers.<OrderItems>lambdaQuery()
                    .in(OrderItems::getSkuId, skuIds));

            // 从这些订单项中获取订单ID，并查询订单状态
            Set<Long> completedOrderIds = orderItems.stream()
                    .map(OrderItems::getOrderId)
                    .distinct()
                    .filter(orderId -> {
                        Orders order = ordersMapper.selectById(orderId);
                        return order != null && order.getOrderStatus() != null && order.getOrderStatus().equals(4); // 4为已完成订单状态
                    })
                    .collect(Collectors.toSet());

            // 汇总已完成订单中这些SKU的销量
            totalSales = orderItems.stream()
                    .filter(item -> completedOrderIds.contains(item.getOrderId()))
                    .mapToInt(item -> Optional.ofNullable(item.getQuantity()).orElse(0))
                    .sum();
        }
        vo.setSales(totalSales);

        return vo;
    }

    // ==== 下载模板 ====
    @Override
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        setExcelResponseHeader(response, "商品导入模板");
        // 提供一行示例数据，方便用户看到各列含义
        List<ProductExcelModel> example = Collections.singletonList(ProductExcelModel.builder().storeName("示例门店")
                .categoryName("示例分类").brandName("示例品牌").name("示例商品").description("示例描述").status(1).build());
        EasyExcel.write(response.getOutputStream(), ProductExcelModel.class).sheet("模板").doWrite(example);
    }

    @Transactional(readOnly = true)
    public void exportProducts(HttpServletResponse response) throws IOException {
        setExcelResponseHeader(response, "商品信息");

        try (ServletOutputStream out = response.getOutputStream()) {
            // 创建ExcelWriter实例
            ExcelWriter excelWriter = EasyExcel.write(out, ProductExportVO.class)
                    .registerConverter(new ImageDataConverter()) // 注册图片转换器
                    .registerWriteHandler(new CustomSheetWriteHandler()) // 注册列宽设置
                    .registerWriteHandler(new CustomRowHeightWriteHandler()) // 注册行高设置
                    .build();

            // 创建工作表
            WriteSheet writeSheet = EasyExcel.writerSheet("商品信息").build();

            int pageSize = 2000;
            int pageNum = 1;

            try {
                while (true) {
                    // 分页查询商品数据
                    Page<Products> page = baseMapper.selectPage(new Page<>(pageNum, pageSize), null);
                    List<Products> productList = page.getRecords();

                    if (CollectionUtils.isEmpty(productList)) {
                        break;
                    }

                    // 转换数据并处理图片
                    List<ProductExportVO> voList = productList.stream().map(p -> {
                        ProductExportVO vo = new ProductExportVO();
                        // 填充基本信息
                        vo.setStoreName(Optional.ofNullable(storesMapper.selectById(p.getStoreId()))
                                .map(Stores::getName).orElse(""));
                        vo.setCategoryName(Optional.ofNullable(categoriesMapper.selectById(p.getCategoryId()))
                                .map(Categories::getName).orElse(""));
                        vo.setBrandName(Optional.ofNullable(brandMapper.selectById(p.getBrandId()))
                                .map(ProductBrands::getName).orElse(""));
                        vo.setName(p.getName());
                        vo.setDescription(p.getDescription());
                        vo.setStatus(p.getStatus());
                        // vo.setPrice(p.getPrice()); // Assuming Products entity has a price o r it's
                        // fetched from SKU elsewhere
                        // vo.setOriginalPrice(p.getOriginalPrice());
                        // vo.setDiscount(p.getDiscount());
                        // 处理主图
                        if (StrUtil.isNotBlank(p.getMainImage())) {
                            try {
                                vo.setPicture(ImageUtils.urlToImageData(p.getMainImage()));
                            } catch (IOException e) {
                                log.error("导出主图处理失败: {}", p.getMainImage(), e);
                            }
                        }

                        // 处理商品多图 (目前 ProductExportVO 仅支持一个图片字段，故移除此处的 firstImage 导出逻辑)
                        // if (StrUtil.isNotBlank(p.getImages())) {
                        // try {
                        // List<String> imagesList = objectMapper.readValue(p.getImages(), new
                        // TypeReference<List<String>>() {});
                        // if (!imagesList.isEmpty()) {
                        // vo.setFirstImage(ImageUtils.getImageByteArray(new URL(imagesList.get(0))));
                        // }
                        // } catch (IOException e) {
                        // log.error("导出多图处理失败: {}", p.getImages(), e);
                        // }
                        // }
                        return vo;
                    }).collect(Collectors.toList());

                    excelWriter.write(voList, writeSheet);

                    if (page.getRecords().size() < pageSize) {
                        break;
                    }
                    pageNum++;
                }
            } finally {
                if (excelWriter != null) {
                    excelWriter.finish();
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importProducts(MultipartFile file) throws IOException {
        Map<Integer, byte[]> pictureMap;
        try (InputStream is = file.getInputStream()) {
            // 提取图片（确保此处不会关闭InputStream，因为它会被EasyExcel再次读取）
            byte[] fileBytes = is.readAllBytes();
            try (InputStream pictureIs = new ByteArrayInputStream(fileBytes)) {
                pictureMap = extractPicturesByOrder(pictureIs);
            }
            try (InputStream excelIs = new ByteArrayInputStream(fileBytes)) {
                // 假设您有一个ProductImportListener来处理导入逻辑
                EasyExcel.read(excelIs, ProductExcelModel.class, new ProductImportListener(ossService, pictureMap))
                        .sheet().doRead();
            }
        }
    }

    private void setExcelResponseHeader(HttpServletResponse resp, String fileName) throws IOException {
        resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        resp.setCharacterEncoding("utf-8");
        String name = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        resp.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + name + ".xlsx");
    }

    private Map<Integer, byte[]> extractPicturesByOrder(InputStream is) throws IOException {
        XSSFWorkbook workbook = new XSSFWorkbook(is);
        XSSFSheet sheet = workbook.getSheetAt(0);
        Map<Integer, byte[]> map = new HashMap<>();

        // 获取所有图片（按在Excel中的顺序）
        List<XSSFPictureData> allPictures = workbook.getAllPictures();

        // 获取数据行范围（关键修复）
        int headerRows = 1; // 标题行数

        // 按顺序分配图片
        for (int i = 0; i < allPictures.size(); i++) {
            // 计算数据行索引
            // +2 是因为 Excel 行号从 1 开始，并且通常第一行为标题行，所以实际数据从第 2 行开始对应索引 1
            // 并且 EasyExcel 读取时默认从第一行数据开始，其索引为0，所以excelRowNum + 1 对应物理行号
            // 这里直接使用 i + 1 作为 map 的 key，对应 Excel 中的行号（如果第一行是数据）
            // 如果第一行是标题，那么数据从第二行开始，对应的索引是 1，所以 map.put(i + 2, data) 是正确的
            map.put(i + 2, allPictures.get(i).getData()); // +2 对应 Excel 物理行号
        }

        workbook.close();
        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateStatus(BatchUpdateStatusDTO dto) {
        if (CollectionUtils.isEmpty(dto.getIds())) {
            throw new ObjectException("ID列表不能为空");
        }
        if (dto.getStatus() == null) {
            throw new ObjectException("状态不能为空");
        }
        LambdaUpdateWrapper<Products> uw = Wrappers.<Products>lambdaUpdate()
                .in(Products::getId, dto.getIds())
                .set(Products::getStatus, dto.getStatus());
        update(uw);
    }

    /**
     * 根据分类ID查询商品，支持价格和销量排序
     * 使用SQL直接查询，避免内存排序
     */
    @Override
    public PageResult<ProductVO> pageProductsByCategory(ProductPageDTO dto) {
        if (dto.getCategoryId() == null) {
            throw new ObjectException("分类ID不能为空");
        }

        // 强制设置状态为已启用
        dto.setStatus(1);

        // 直接调用通用的pageProducts方法，复用逻辑
        return pageProducts(dto);
    }

    @Override
    public List<ProductVO> getPopularProducts() {
        ProductPageDTO dto = new ProductPageDTO();
        dto.setPageNum(1);
        dto.setPageSize(10);
        dto.setStatus(1);
        dto.setSortBy("sales");
        dto.setSortOrder("desc");
        PageResult<ProductVO> pageResult = pageProducts(dto);
        return pageResult.getItems();
    }

    @Override
    public List<ProductVO> getNewProducts() {
        ProductPageDTO dto = new ProductPageDTO();
        dto.setPageNum(1);
        dto.setPageSize(10);
        dto.setStatus(1);
        dto.setSortBy("create_time");
        dto.setSortOrder("desc");
        PageResult<ProductVO> pageResult = pageProducts(dto);
        return pageResult.getItems();
    }

    @Override
    public List<ProductVO> getProductsByCategory(Long categoryId) {
        ProductPageDTO dto = new ProductPageDTO();
        dto.setPageNum(1);
        dto.setPageSize(20);
        dto.setStatus(1);
        dto.setCategoryId(categoryId.intValue());
        PageResult<ProductVO> pageResult = pageProducts(dto);
        return pageResult.getItems();
    }

    @Override
    public PageResult<ProductVO> searchProducts(ProductSearchDTO searchDTO) {
        // 将搜索DTO转换为页面DTO，复用已有的pageProducts逻辑
        ProductPageDTO dto = new ProductPageDTO();
        dto.setPageNum(searchDTO.getPageNum());
        dto.setPageSize(searchDTO.getPageSize());
        dto.setStatus(1); // 只搜索上架商品
        dto.setName(searchDTO.getKeyword());
        if (searchDTO.getCategoryId() != null) {
            dto.setCategoryId(searchDTO.getCategoryId().intValue());
        }
        dto.setSortBy(searchDTO.getSortBy());
        dto.setSortOrder(searchDTO.getSortOrder());

        return pageProducts(dto);
    }

    @Override
    public ProductDetailVO getProductDetail(Long id) {
        Products entity = baseMapper.selectById(id.intValue());
        if (entity == null)
            throw new ObjectException("商品不存在: " + id);

        ProductVO productVO = toVO(entity);
        ProductDetailVO detailVO = BeanUtil.copyProperties(productVO, ProductDetailVO.class);

        // 查询商品SKU
        LambdaQueryWrapper<ProductSku> skuQw = Wrappers.<ProductSku>lambdaQuery()
                .eq(ProductSku::getProductId, id.intValue())
                .eq(ProductSku::getSaleable, true)
                .eq(ProductSku::getValid, true);
        List<ProductSku> skus = productSkuMapper.selectList(skuQw);

        // 转换SKU为VO
        List<SkuVO> skuVOList = new ArrayList<>();
        for (ProductSku sku : skus) {
            SkuVO skuVO = new SkuVO();
            skuVO.setId(sku.getId().longValue());
            skuVO.setSkuCode(sku.getSkuCode());
            skuVO.setPrice(sku.getPrice());
            skuVO.setStock(sku.getStock());
            skuVO.setSpecs(sku.getSpecs());
            skuVOList.add(skuVO);
        }

        detailVO.setSkuList(skuVOList);

        return detailVO;
    }

    @Override
    public Object getProductSalesData(Integer productId) {
        // 获取商品销售数据
        Map<String, Object> salesData = new HashMap<>();

        try {
            // 1. 查询商品总销量
            Integer totalSales = orderItemsMapper.getTotalSalesByProduct(productId);
            salesData.put("totalSales", totalSales != null ? totalSales : 0);

            // 2. 查询商品总收入
            BigDecimal totalRevenue = orderItemsMapper.getTotalRevenueByProduct(productId);
            salesData.put("totalRevenue", totalRevenue != null ? totalRevenue : BigDecimal.ZERO);

            // 3. 查询商品评价数
            Integer ratings = reviewsMapper.getReviewCountByProduct(productId);
            salesData.put("ratings", ratings != null ? ratings : 0);
        } catch (Exception e) {
            log.error("获取商品销售数据失败: productId={}", productId, e);
            // 出错时返回默认值
            salesData.put("totalSales", 0);
            salesData.put("totalRevenue", BigDecimal.ZERO);
            salesData.put("ratings", 0);
        }

        return salesData;
    }
}
